source "ta.tcl"
 
proc SortBy {tree col direction} {
	set data {}
	foreach row [$tree children {}] {
		lappend data [list [$tree set $row $col] $row]
	}
	set dir [expr {$direction ? "-decreasing" : "-increasing"}]
	set r -1
 
	foreach info [lsort -dictionary -index 0 $dir $data] {
		$tree move [lindex $info 1] {} [incr r]
	}
 
	$tree heading $col -command [list SortBy $tree $col [expr {!$direction}]]
}
 
proc RefleshCanvas {canvas graph_style filtered_table indicator_name} {
	$canvas delete "all"
 
	set res {}
	set x {}
	set open {}
	set close {}
	set high {}
	set low {}
	set labels {}
 
	for {set i 0} {$i<[llength $filtered_table]} {incr i} {
		set row [lindex $filtered_table $i]
		lappend open [lindex $row 2]	
		lappend high [lindex $row 3]	
		lappend low [lindex $row 4]	
		lappend close [lindex $row 5]	
		lappend res [lindex $row 5]
		lappend labels [lindex $row 0]
	}
 
	# Draw indicator
	set len [llength $res]	
	set sorted [lsort -real $res]
	set ymax [lindex $sorted end]
	set ymin [lindex $sorted 0]
 
	set xmax $len	
 
	# Draw data
	if {$graph_style == "Simple"} {
		PlotXY $canvas $res
		RefleshIndicator $canvas $filtered_table $indicator_name $xmax $ymin $ymax
	} elseif {$graph_style == "Candle Stick"} {
		PlotCandleSticks $canvas $labels $res $open $close $low $high
		RefleshIndicator $canvas $filtered_table $indicator_name $xmax $ymin $ymax		
	}
}
 
proc PlotCandleSticks {canvas labels x open close low high} {
	$canvas delete "all"		
	set width [$canvas cget -width]
	set height [$canvas cget -height]
	set border 40
	set graph_w [expr {$width - 2*$border}]
	set graph_h [expr {$height - 2*$border}]
 
	set len [llength $close]	
	set ymax [lindex [lsort -real $high] end]
	set ymin [lindex [lsort -real $low] 0]
	set xmax $len
 
	set x_orig $border
	set y_orig [expr {$height - $border}]
	set x_scale [expr {$graph_w / $xmax}]
	set y_scale [expr {$graph_h / [ expr {$ymax - $ymin}]}]
	set psize 2 	
	set nstep 10	
 
	## draw x-axis, y-aix
	$canvas create line $x_orig $y_orig $graph_w $y_orig  -width 1
	$canvas create line $x_orig $y_orig $x_orig $border -width 1	
 
	## draw tick on y-axis
	DrawTicks $canvas $ymin $ymax $nstep $y_scale $x_orig $y_orig $border 	
 
	for {set i 0} {$i<[llength $labels]} {incr i} {
		set open_i [lindex $open $i]
		set close_i [lindex $close $i]
		set low_i [lindex $low $i]
		set high_i [lindex $high $i]
		drawACandle $canvas $i $open_i $close_i $low_i $high_i $xmax $ymax $ymin
	}
}
 
 
proc drawACandle {canvas i open close low high xmax ymax ymin} {
	set width [$canvas cget -width]
	set height [$canvas cget -height]
	set border 40
	set graph_w [expr {$width - 2*$border}]
	set graph_h [expr {$height - 2*$border}]
 
	set x_orig $border
	set y_orig [expr {$height - $border}]
	set x_scale [expr {$graph_w / $xmax}]
	set y_scale [expr {$graph_h / [ expr {$ymax - $ymin}]}]
	set psize 2 	
 
	set x_value $i
	set x [expr {$x_orig + $x_scale * $x_value}]
	set y_open [expr {$y_orig - $y_scale * [expr {$open - $ymin}]}]
	set y_close [expr {$y_orig - $y_scale * [expr {$close - $ymin}]}]
	set y_low [expr {$y_orig - $y_scale * [expr {$low - $ymin}]}]
	set y_high [expr {$y_orig - $y_scale * [expr {$high - $ymin}]}]
 
	set x1 [expr {$x - 2}]
	set x2 [expr {$x + 2}]
	$canvas create line $x $y_low $x $y_high -width 1	-fill red
	$canvas create rect $x1 $y_open $x2 $y_close -width 1 -fill white
}
 
proc PlotBollinger {canvas data_table xmax ymin ymax} {
	set xy_value [computeSMA $data_table] 
	set high_xy_value {}
	set low_xy_value {}
 
	set x {}
	for {set i 0} {$i<[llength $data_table]} {incr i} {
		set row [lindex $data_table $i]
		lappend x [lindex $row 5]
	}		
 
	set sum 0
	set sum_x2 0
 
	for {set i 0} {$i<[llength $x]} {incr i} {
		set x_i [lindex $x $i]
		set sum [expr {$sum + $x_i}]
		set x_2 [expr {$x_i * $x_i}]
		set sum_x2 [expr {$sum_x2 + $x_2}]
	}
 
	set n [llength $x]
 
	set x_bar [expr {$sum / $n}]
	set x_bar_2 [expr {$x_bar * $x_bar}]
	set sum [expr {$sum * $sum}]
 
	set dev [expr {$sum_x2 / $n}]
	set dev [expr {$dev - $x_bar_2}]
	set dev [expr {sqrt($dev)}]
 
	for {set i 0} {$i<[llength $xy_value]} {incr i} {
		set row [lindex $xy_value $i]
		set x [lindex $row 0]
		set y [lindex $row 1]
		lappend high_xy_value [list $i [expr {$y + 2*$dev}]]
		lappend low_xy_value [list $i [expr {$y - 2*$dev}]]
	}	
	PlotIndicator $canvas $high_xy_value $xmax $ymin $ymax
	PlotIndicator $canvas $low_xy_value $xmax $ymin $ymax
}	
 
proc RefleshIndicator {canvas data_table name xmax ymin ymax} {
	switch $name {
		"SMA" { 
			set xy_value [computeSMA $data_table] 
			PlotIndicator $canvas $xy_value $xmax $ymin $ymax
		}
		"EMA" { 
			set xy_value [computeEMA $data_table]
			PlotIndicator $canvas $xy_value $xmax $ymin $ymax	
		}
		"ZigZag" { 
			set xy_value [computeZigZag $data_table] 
			PlotIndicator $canvas $xy_value $xmax $ymin $ymax
		}
		"Bollinger Bands" { 
			PlotBollinger $canvas $data_table $xmax $ymin $ymax			
		}		
	}
}
 
proc FilterDataFromStartDateToEndDate {data_table start_date end_date} {
	set filtered_table {}
 
	foreach row $data_table {
		set date [lindex $row 0]
		set x [lindex $row 1]
		set open [lindex $row 2]
		set high [lindex $row 3]
		set low [lindex $row 4]
		set close [lindex $row 5]
		set volumn [lindex $row 6]
		set b1 [expr {[string compare $date $start_date] == 1}]
		set b2 [expr {[string compare $date $end_date] == -1}]
		set b3 [expr {$b1 && $b2}]
		if {$b3} {
			lappend filtered_table [list $date $x $open $high $low $close $volumn]	
		}
	}
 
	return $filtered_table
}
 
proc PlotXY {canvas res} {	
	$canvas delete "all"
	set width [$canvas cget -width]
	set height [$canvas cget -height]
	set border 40
	set graph_w [expr {$width - 2*$border}]
	set graph_h [expr {$height - 2*$border}]
 
	set len [llength $res]	
	set sorted [lsort -real $res]
	set ymax [lindex $sorted end]
	set ymin [lindex $sorted 0]
 
	set xmax $len
	set nstep 10
	set x_orig $border
	set y_orig [expr {$height - $border}]
	set x_scale [expr {$graph_w / $xmax}]
	set y_scale [expr {$graph_h / [ expr {$ymax - $ymin}]}]
	set psize 2 
 
	## draw x-axis, y-aix
	$canvas create line $x_orig $y_orig $graph_w $y_orig  -width 1
	$canvas create line $x_orig $y_orig $x_orig $border -width 1	
 
	## draw tick on y-axis
	DrawTicks $canvas $ymin $ymax $nstep $y_scale $x_orig $y_orig $border 
 
	set last_x $x_orig
	set last_y $y_orig
 
	for {set i 0} {$i<[llength $res]} {incr i} {
		set x_value [expr {$i+1}]
		set y_value [lindex $res $i]
		set x [expr {$x_orig + $x_scale * $x_value}]
		set y [expr {$y_orig - $y_scale * [expr {$y_value-$ymin}]}]
		#set point [$canvas create oval [expr {$x-$psize}] [expr {$y-$psize}] \
			[expr {$x+$psize}] [expr {$y+$psize}] -width 1 -fill SkyBlue2]
		#$canvas addtag point withtag $point
 
		$canvas create line $last_x $last_y $x $y -width 1
		set last_x $x
		set last_y $y
	}
}
 
proc DrawTicks {canvas ymin ymax nstep y_scale x_orig y_orig border} {
	set y $ymin
	set x1 [expr {$x_orig - 4}]
	set x2 $x_orig
	set step [expr { [expr {$ymax - $ymin}] / $nstep}]
 
	while {$y < $ymax} {
		set tick [expr {$y_orig - $y_scale * [expr {$y-$ymin}]}]
		if {$tick > $border} {
			$canvas create line $x1 $tick $x2 $tick -width 1 
		}
		set y [expr {$y + $step}]
	}
}
 
proc PlotIndicator {canvas xy_value xmax ymin ymax} {
	set width [$canvas cget -width]
	set height [$canvas cget -height]
	set border 40
	set graph_w [expr {$width - 2*$border}]
	set graph_h [expr {$height - 2*$border}]
 
	set x_orig $border
	set y_orig [expr {$height - $border}]
	set x_scale [expr {$graph_w / $xmax}]
	set y_scale [expr {$graph_h / [ expr {$ymax - $ymin}]}]
 
	set last_x $x_orig
	set last_y $y_orig
 
	for {set i 0} {$i<[llength $xy_value]} {incr i} {
		set row [lindex $xy_value $i]
		set x_value [expr {[lindex $row 0]}]
		set y_value [lindex $row 1]
		set x [expr {$x_orig + $x_scale * $x_value}]
		set y [expr {$y_orig - $y_scale * [expr {$y_value-$ymin}]}]
		$canvas create line $last_x $last_y $x $y -width 1 -fill green
		set last_x $x
		set last_y $y
	}		
}